package top.jfunc.common.db.data;

import org.springframework.util.Assert;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 处理批量任务中的单个条目
 * <p>
 * 可以让用户自定义每个条目（item）将其填充到语句（PreparedStatement）中
 *
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
 * @since 1.0 2022/11/26 13:02
 */
public interface BatchStatementCallback<T> {

	/**
	 * 填充数据到SQL语句中
	 *
	 * @param item 单个条目
	 * @param statement 编译后的 SQL 语句
	 * @throws SQLException 填充过程中可能的异常
	 */
	void applyTo(T item, PreparedStatement statement) throws Exception;

	/**
	 * 直接将 ResultSet 映射到 PreparedStatement
	 * <p>
	 * 从第一列开始映射 一直映射 {@code columns} 个列
	 *
	 * @param columns 列数
	 */
	static BatchStatementCallback<ResultSet> forColumns(int columns) {
		return forColumns(1, columns);
	}

	/**
	 * 直接将 ResultSet 映射到 PreparedStatement
	 * <p>
	 * 从 {@code startColumn} 起 一直映射 {@code columns} 个列
	 *
	 * @param columns 列数
	 * @param startColumn 起始列，从指定的列开始映射
	 */
	static BatchStatementCallback<ResultSet> forColumns(int startColumn, int columns) {
		return new ResultSetAsIs(startColumn, columns);
	}

	/**
	 * 直接将 ResultSet 映射到 PreparedStatement
	 */
	static BatchStatementCallback<ResultSet> autoColumns() {
		return new AutoColumns();
	}

	class AutoColumns implements BatchStatementCallback<ResultSet> {

		int columnCount = -1;

		@Override
		public void applyTo(ResultSet item, PreparedStatement statement) throws Exception {
			int columnCount = this.columnCount;
			if (columnCount == -1) {
				columnCount = item.getMetaData().getColumnCount();
				this.columnCount = columnCount;
			}
			for (int i = 1; i <= columnCount; i++) {
				statement.setObject(i, item.getObject(i));
			}
		}

	}

	class ResultSetAsIs implements BatchStatementCallback<ResultSet> {

		final int startColumn;
		final int endColumn;

		public ResultSetAsIs(int startColumn, int columns) {
			Assert.isTrue(columns > 0, "映射列数必须大于0");
			Assert.isTrue(startColumn >= 1, "起始位置必须大于等于0");
			this.startColumn = startColumn;
			this.endColumn = startColumn + columns - 1;
		}

		@Override
		public void applyTo(ResultSet item, PreparedStatement statement) throws SQLException {
			for (int i = startColumn; i <= endColumn; i++) {
				statement.setObject(i, item.getObject(i));
			}

		}
	}

}